package com.ttg.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Objects;
import java.util.Optional;

/**
 * @author huyangzou
 * @create 2021-01-05 15:48
 */
public class BigDecimalUtil {

    private static final String CNY = "CNY";

    /**
     * BigDecimal判断是否空值
     *
     * @return boolean
     */
    private static boolean isNull(BigDecimal bigDecimal) {
        return bigDecimal == null;
    }

    /**
     * BigDecimal判断是否空值
     *
     * @return boolean
     */
    private static boolean isNull(String bigDecimal) {
        return StringUtils.isBlank(bigDecimal);
    }

    /**
     * 除法
     * bigDecimal为NULL则返回null不计算
     * divisor为NULL则返回bigDecimal不计算
     *
     * @return BigDecimal
     */
    public static BigDecimal divide(BigDecimal bigDecimal, BigDecimal divisor) {
        if (isNull(bigDecimal)) {
            return null;
        } else if (isNull(divisor)) {
            return bigDecimal;
        } else {
            return bigDecimal.divide(divisor, 2, BigDecimal.ROUND_HALF_UP);
        }
    }

    /**
     * @param bigDecimal 除数
     * @param divisor    被除数
     */
    public static String toPercentage(BigDecimal bigDecimal, BigDecimal divisor) {
        BigDecimal origin = BigDecimalUtil.divide(bigDecimal, divisor);
        BigDecimal percentage = BigDecimalUtil.yuanToFen(origin);
        return percentage.toString() + "%";
    }

    /**
     * 除法
     * a
     *
     * @return BigDecimal
     */
    private static double divide(Long a) {
        if (Objects.isNull(a)) {
            return Double.parseDouble(null);
        } else {
            return a.doubleValue() / Long.valueOf(100L).doubleValue();
        }
    }

    /**
     * 乘法
     * bigDecimal为NULL则返回null不计算
     * multiplicand为NULL则返回bigDecimal不计算
     *
     * @return BigDecimal
     */
    private static BigDecimal multiply(BigDecimal bigDecimal, BigDecimal multiplicand) {
        if (isNull(bigDecimal)) {
            return null;
        } else if (isNull(multiplicand)) {
            return bigDecimal;
        } else {
            return bigDecimal.multiply(multiplicand).setScale(0, BigDecimal.ROUND_HALF_UP);
        }
    }

    /**
     * 元转分
     *
     * @param yuan 元
     * @return 分
     */
    public static BigDecimal yuanToFen(BigDecimal yuan) {
        return multiply(yuan, new BigDecimal("100"));
    }

    /**
     * 分转元
     *
     * @param fen 分
     * @return 元
     */
    public static BigDecimal fenToYuan(BigDecimal fen) {
        return divide(fen, new BigDecimal("100"));
    }

    /**
     * 分转元
     *
     * @param fen 分
     * @return 元
     */
    public static double fenToYuan(Long fen) {
        BigDecimal fenBigDecimal = new BigDecimal(fen);
        return fenToYuan(fenBigDecimal).doubleValue();
    }

    /**
     * 元转分
     *
     * @param yuan 元
     * @return 分
     */
    public static BigDecimal yuanToFen(String yuan) {
        if (isNull(yuan)) {
            return null;
        }
        return multiply(new BigDecimal(yuan), new BigDecimal("100"));
    }

    /**
     * 分转元
     *
     * @param fen 分
     * @return 元
     */
    public static BigDecimal fenToYuan(String fen) {
        if (isNull(fen)) {
            return null;
        }
        return divide(new BigDecimal(fen), new BigDecimal("100"));
    }


    /**
     * @param fen 单位为分
     * @return 单位为元，格式为：CNY#####.##
     */
    public static String fenToYuanCNY(String fen) {
        if (!StringUtils.isNumeric(fen)) {
            throw new IllegalArgumentException();
        }
        BigDecimal yuan = divide(new BigDecimal(fen), new BigDecimal("100"));
        return CNY + yuan;
    }

    /**
     * 分转元
     *
     * @param fen 分
     * @return 元
     */
    public static BigDecimal fenToYuanFromLong(Long fen) {
        if (isNull(fen == null ? null : fen.toString())) {
            return null;
        }
        return divide(new BigDecimal(fen), new BigDecimal("100"));
    }

    /**
     * 分转元，并格式化保留两位小数
     *
     * @param fen 分
     */
    public static String fenToYuanToString(BigDecimal fen) {
        BigDecimal yuan = fenToYuan(fen);
        DecimalFormat df = new DecimalFormat("0.00");
        return df.format(yuan);
    }

    /**
     * 元转字符串，并格式化保留两位小数
     */
    public static String yuanToString(BigDecimal yuan) {
        DecimalFormat df = new DecimalFormat("0.00");
        df.setRoundingMode(RoundingMode.HALF_EVEN);
        return df.format(yuan);
    }

    /**
     * 分转元，并格式化保留两位小数
     *
     * @param fen 分
     */
    public static String fenToYuanToStringFromLong(Long fen) {
        BigDecimal yuan = fenToYuanFromLong(fen);
        DecimalFormat df = new DecimalFormat("0.00");
        return df.format(yuan);
    }

    /**
     * 分转元
     *
     * @param fen 分
     * @return 元
     */
    public static String fenToYuan(int fen) {
        return String.valueOf(divide(new BigDecimal(fen), new BigDecimal(100)));
    }


    /**
     * 分转元
     *
     * @param fen 分
     * @return 元
     */
    public static BigDecimal fenToYuanHaveTwo(Object fen) {

        if (StringUtils.isBlank(String.valueOf(fen))) {
            return null;
        }
        BigDecimal bigDecimal = divide(new BigDecimal(fen.toString()), new BigDecimal("100"));

        DecimalFormat df = new DecimalFormat("0.00");
        String str2 = df.format(bigDecimal);
        return new BigDecimal(str2);
    }


    /**
     * 格式化保留两位小数（舍掉）
     *
     * @param num 数据
     * @return 两位小数
     */
    public static String formatTwoDecimal(String num) {
        if (isNull(num)) {
            return null;
        }
        BigDecimal bigDecimal = new BigDecimal(num);
        BigDecimal result = BigDecimal.ZERO.add(bigDecimal.setScale(2, RoundingMode.FLOOR));
        return result.toString();
    }


    /**
     * 用于分转元，保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @return
     */
    public static String f2yNullZero(@Nullable String fen) {
        return f2yNullZeroO(fen, null);
    }

    /**
     * 用于分转元，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @return
     */
    public static String f2yNullZero(@Nullable Integer fen) {
        return f2yNullZeroO(fen, null);
    }

    /**
     * 用于分转元，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @return
     */
    public static String f2yNullZero(@Nullable Long fen) {
        return f2yNullZeroO(fen, null);
    }

    /**
     * 用于分转元，可以选格式，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @return
     */
    public static String f2yNullZero(@Nullable BigDecimal fen) {
        return f2yNullZeroO(fen, null);
    }

    /**
     * 用于分转元，可以选格式，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @return
     */
    public static String f2yNullZero(@Nullable Double fen) {
        return f2yNullZeroO(fen, null);
    }

    /**
     * 用于分转元，可以选格式，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @param df  需要的格式，默认保留两位小数
     * @return
     */
    public static String f2yNullZero(@Nullable String fen, @Nullable DecimalFormat df) {
        return f2yNullZeroO(fen, df);
    }

    /**
     * 用于分转元，可以选格式，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @param df  需要的格式，默认保留两位小数
     * @return
     */
    public static String f2yNullZero(@Nullable Integer fen, @Nullable DecimalFormat df) {
        return f2yNullZeroO(fen, df);
    }

    /**
     * 用于分转元，可以选格式，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @param df  需要的格式，默认保留两位小数
     * @return
     */
    public static String f2yNullZero(@Nullable Long fen, @Nullable DecimalFormat df) {
        return f2yNullZeroO(fen, df);
    }

    /**
     * 用于分转元，可以选格式，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @param df  需要的格式，默认保留两位小数
     * @return
     */
    public static String f2yNullZero(@Nullable BigDecimal fen, @Nullable DecimalFormat df) {
        return f2yNullZeroO(fen, df);
    }

    /**
     * 用于分转元，可以选格式，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @param df  需要的格式，默认保留两位小数
     * @return
     */
    public static String f2yNullZero(@Nullable Double fen, @Nullable DecimalFormat df) {
        return f2yNullZeroO(fen, df);
    }


    /**
     * 用于分转元，可以选格式，默认保留两位小数
     *
     * @param fen 分 如果传入nnull 则返回0
     * @param df
     * @return
     */
    private static String f2yNullZeroO(Object fen, DecimalFormat df) {
        BigDecimal yuan = BigDecimal.ZERO;
        if (Objects.nonNull(fen)) {
            String type = fen.getClass().getSimpleName();
            switch (type) {
                case "String":
                    yuan = fenToYuan((String) fen);
                    break;
                case "Integer":
                    yuan = fenToYuan(new BigDecimal((Integer) fen));
                    break;
                case "Long":
                    yuan = fenToYuan(new BigDecimal((Long) fen));
                    break;
                case "BigDecimal":
                    yuan = fenToYuan((BigDecimal) fen);
                    break;
                case "Double":
                    yuan = fenToYuan(BigDecimal.valueOf((Double) fen));
                    break;
            }
        }
        df = Optional.ofNullable(df).orElse(new DecimalFormat("#0.00"));
        return df.format(yuan);
    }


}
